using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace CGShaderIntegration.DrawableGameComponents
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class PaulheimAnnikaGameComponent : Microsoft.Xna.Framework.DrawableGameComponent, IMatrices
    {

        //GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Model erde;
        Model mond;
        Model sonne;

        Matrix worldMatrix;
        Matrix viewMatrix;
        Matrix projectionMatrix;
        Vector3 erdePosition;
        Vector3 mondPosition;
        Vector3 sonnePosition;
        Matrix erdeWorldMatrix;
        Matrix mondWorldMatrix;
        Matrix sonneWorldMatrix;
        float direction;

        Effect schachbrett;
        Effect tiefenshader;


        public Matrix WorldMatrix
        {
            get
            {
                return this.worldMatrix;
            }
            set
            {
                this.worldMatrix = value;
            }
        }

        public Matrix ViewMatrix
        {
            get
            {
                return this.viewMatrix;
            }
            set
            {
                this.viewMatrix = value;
            }
        }

        public Matrix ProjectionMatrix
        {
            get
            {
                return this.projectionMatrix;
            }
            set
            {
                this.projectionMatrix = value;
            }
        }
        
        
        public PaulheimAnnikaGameComponent(Game game)
            : base(game)
        {
            
            game.Components.Add(this);
        }

        

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            worldMatrix = Matrix.Identity;

            erdePosition = new Vector3(5.0f, 0.0f, 0.0f);
            mondPosition = new Vector3(2.0f, 0.0f, 0.0f);
            sonnePosition = new Vector3(0.0f, 0.0f, 0.0f);

            

            direction = 1.0f;
            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            
            erde = Game.Content.Load<Model>("models\\PaulheimAnnikaPlanet");
            mond = Game.Content.Load<Model>("models\\PaulheimAnnikaPlanet");
            sonne = Game.Content.Load<Model>("models\\PaulheimAnnikaPlanet");

            schachbrett = Game.Content.Load<Effect>("effects\\PaulheimAnnikaSchachbrett");
            tiefenshader = Game.Content.Load<Effect>("effects\\PaulheimAnnikaTiefenshader");

        }

        protected override void UnloadContent()
        {
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            int time = (int)gameTime.TotalGameTime.Seconds * 1000 + gameTime.TotalGameTime.Milliseconds;
            erdeWorldMatrix = Matrix.CreateScale(0.5f) * Matrix.CreateTranslation(erdePosition) * Matrix.CreateRotationY(direction * (((float)(time % 10000) / (float)10000)) * 2 * (float)Math.PI) * WorldMatrix;
            mondWorldMatrix = Matrix.CreateScale(0.2f) * Matrix.CreateTranslation(mondPosition) * Matrix.CreateRotationY(direction * (((float)(time % 2000) / (float)2000)) * 2 * (float)Math.PI) * erdeWorldMatrix;
            sonneWorldMatrix = Matrix.CreateScale(2.0f) * WorldMatrix;

            if (Keyboard.GetState().IsKeyDown(Keys.Space))
                direction *= -1.0f;

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            foreach (ModelMesh mesh in erde.Meshes)
            {
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                {
                    meshPart.Effect = tiefenshader;
                    meshPart.Effect.Parameters["fvEyePosition"].SetValue(new Vector3(6.0f, 0.0f, 0.0f));
                    meshPart.Effect.Parameters["matViewProjection"].SetValue(viewMatrix * projectionMatrix);
                    meshPart.Effect.Parameters["world"].SetValue(erdeWorldMatrix);
                    meshPart.Effect.Parameters["fNearClipPlane"].SetValue(4.0f);
                    meshPart.Effect.Parameters["fFarClipPlane"].SetValue(6.0f);                    
                }
                try
                {
                    mesh.Draw();
                }
                catch (InvalidOperationException e)
                {
                }
            }

            foreach (ModelMesh mesh in mond.Meshes)
            {
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                {
                    meshPart.Effect = schachbrett;
                    meshPart.Effect.Parameters["matViewProjection"].SetValue(viewMatrix * projectionMatrix);
                    meshPart.Effect.Parameters["world"].SetValue(mondWorldMatrix);
                }
                try
                {
                    mesh.Draw();
                }
                catch (InvalidOperationException e)
                {
                }
            }

            
            foreach (ModelMesh mesh in sonne.Meshes)
            {
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                {
                    meshPart.Effect = schachbrett;
                    meshPart.Effect.Parameters["matViewProjection"].SetValue(viewMatrix * projectionMatrix);
                    meshPart.Effect.Parameters["world"].SetValue(sonneWorldMatrix);
                }
                try
                {
                    mesh.Draw();
                }
                catch (InvalidOperationException e)
                {
                }
            }

            base.Draw(gameTime);
        }

        public String GetName()
        {
            return "PaulheimAnnika";
        }
    }
}
